#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include "miniscript.config.h"
#include "miniscript.h"

#define SIZE_STACK 0x40
#define SIZE_SCOPE 0x40
#define SIZE_POOL 0x04
#define SIZE_POOLA 0x01

typedef struct
{
    Stack base;
    Var vars[SIZE_STACK];
} MyStack;

typedef struct
{
    Scope base;
    VarMap nvars[SIZE_SCOPE];
} MyScope;

typedef struct
{
    Pool base;
    ObjectForPool objs[SIZE_POOL];
} MyPool;

typedef struct
{
    ArrayPool base;
    ArrayForPool arrs[SIZE_POOLA];
} MyArrayPool;

Var Stack_OVERFLOW;

void gf_print(Thread *p)
{
    Var v = *Stack_pop(p->s);
    Var__(Stack_pop(p->s));
    Var__(Stack_pop(p->s));

    Var *pv = (v.vt == VT_Refer) ? v.ref : &v;
    if (pv->vt == VT_Number)
    {
        printf("%d\n", pv->num);
    }
    else if (pv->vt == VT_CodeString)
    {
        const char *b = pv->code;
        const char *p = b + 1;
        while (*p != *b)
            printf("%c", *(p++));
        printf("\n");
    }
    else
    {
        printf("VT: %d\n", pv->vt);
    }

    Var__(&v);
    Stack_push(p->s); //void
}

#define SIZE_SRC 0x1000
#define FROM_FILE 0x01

int main(int argc, char* argv[])
{
    if (argc < 1) {
        printf("usage: ./xxx sample.js\r\n");
        return -1;
    }

#ifdef FROM_FILE
    char *filepath = argv[1];
    int fd = open(filepath, O_RDONLY);

    if (fd == -1) {
      printf("can not open the file\n");
      return 1;
    }
#else
    int fd = 0; // 表示来自标准输入
#endif

    char buf[SIZE_SRC];
    size_t n = 0;

    ssize_t r;
    while (0 < (r = read(fd, buf + n, SIZE_SRC - n)))
        n += r;
    buf[n] = '\0';

    {
        MyPool pool;                                                // 请注意MyPool与Pool的区别
        Pool_global(Pool_(&pool.base, SIZE_POOL));                  // 初始化池

        MyArrayPool poola;
        ArrayPool_global(ArrayPool_(&poola.base, SIZE_POOLA));      // 初始化数组对象池子

        MyStack stack;
        Stack_(&stack.base, SIZE_STACK);                            // 初始化栈。实际保存值的

        MyScope scope;
        Scope_(&scope.base, SIZE_SCOPE);                            // 初始化作用域

        Thread thread;
        Thread_(&thread, buf, &stack.base, &scope.base);            // 初始化虚拟机对象

        Var *pv;
        pv = Scope_add(thread.o, "print", 5, Stack_push(thread.s)); // 将print方法注册到当前作用域
        {
            pv->vt = VT_Function;
            pv->func = gf_print;
        }
        pv = Scope_add(thread.o, "Array", 5, Stack_push(thread.s)); // 将Array方法注册到当前作用域
        {
            pv->vt = VT_Function;
            pv->func = mslib_Array;
        }

        Stack_ground(thread.s);                                     // 作用域添加了新的值，栈需要遍历到栈顶

        Error *e = Thread_run(&thread);                             // 执行虚拟机
        if (e)
        {
            char a[0x10];
            strncpy(a, e->code, e->len)[e->len] = '\0';
            printf("[ERROR!] %s('%s')\n", e->reason, a);
        }

        dump(thread.s);
        dumpo(thread.o);

        Thread__(&thread);                                          // 退出虚拟机
        Scope__(&scope.base);                                       // 退出作用域
        Stack__(&stack.base);                                       // 退出栈
        ArrayPool__(&poola.base);                                   // 销毁数组对象池
        Pool__(&pool.base);                                         // 销毁池
    }

    return 0;
}
